<script setup lang="ts">
import { ref, onMounted } from 'vue'
import {MyWebsocket} from "/@/utils/websocket/websocket"
import { Websocket, WebsocketEvent } from 'websocket-ts'
import  { MessageType } from '/@/utils/websocket/messageEnum'
import type { WebSocketMessageContentType } from '/@/utils/websocket/messageEnum'
import { ElMessage } from 'element-plus'
// 定义 video 元素的引用
const localVideo = ref<HTMLVideoElement>();
const remoteVideo = ref<HTMLVideoElement>();


// 定义rtc连接
let pc: RTCPeerConnection | null = null;
// 定义本地的 localStream
let localStream: MediaStream  = new MediaStream();
// 定义远程的 remoteStream
let remoteStream: MediaStream | null = null;
// 用于显示连接信息
const textArea = ref<string>("开始");
const roomId=ref<number>()
const userId=ref<number>()

let ws:MyWebsocket|null=null

// 获取本地摄像头并播放
const getCamera = async () => {
  try {
    console.log("开始获取摄像头")
    // 获取媒体设备信息
    const navigator = window.navigator.mediaDevices;
    //判断用户是否拥有摄像头
    const devices = await navigator.enumerateDevices();
// 如果存在媒体设备，获取摄像头视频流
    if (devices) {
      // 请求用户媒体设备（摄像头）
      const stream = await navigator.getUserMedia({
        audio: false,
        video: true,
        // video: {
        //   width: 400, // 设置视频宽度
        //   height: 300, // 设置视频高度
        //   facingMode: "user", // 使用前置摄像头
        // },
      });
      localStream=stream
      // 如果视频元素存在，将视频流绑定到视频元素上并开始播放
      if (localVideo.value) {
        localVideo.value.srcObject = stream;
        localVideo.value.play();
      }
      console.log("开始获取摄像头成功")
    }else {
      ElMessage.error('对不起，没有摄像头')
    }
  } catch (error) {
    console.error('获取摄像头失败:', error);
  }
};

onMounted(() => {
  console.log("页面加载完毕")
  console.log(remoteVideo)
  console.log(remoteVideo.value)

});

const clickStart=async()=>{
  console.log("roomId:",roomId.value,"userId:",userId.value)

  if(!roomId.value){
    // 提示用户输入房间号和用户id
    ElMessage.error('对不起，请输入你的roomid')
    return
  }

  if(!userId.value){
    ElMessage.error('对不起，请输入你的用户id')
    return
  }
  // 调用本地摄像头
  await getCamera();
  console.log("构建websocket连接")
  // 构建websocket连接
  ws = new MyWebsocket(null,userId.value,roomId.value);
  // step 1: 和信令服务器进行连接。
  // 使用信令服务器来交换WebRTC连接所需的SDP（Session Description Protocol）和ICE（Interactive Connectivity Establishment）候选信息。
  ws.setOnConnect(()=>{
    // 连接成功后，发送需要连接的房间信息
    const data={
      type: MessageType.AddRoom,
      data:roomId.value,
      id:roomId.value
    }
    console.log("开始发送添加房间的请求",data)
    ws?.send(data)
    console.log("开始连接webrtc")
    createPeerConnection()
  })

  // step 2: 收到信令服务器的响应，创建一个RTCPeerConnection实例，用于创建WebRTC连接。
  // step 2: 收到信令服务器的响应，创建一个 RTCPeerConnection 实例
  ws.setOnMessage((result:any)=>{
    console.log("收到消息",result)
    const data:WebSocketMessageContentType = JSON.parse(result);
    handleSignalingMessage(data);
  })

}

// 处理信令消息
const handleSignalingMessage = (data: WebSocketMessageContentType) => {
  // 如果还没有创建 RTCPeerConnection，则创建一个
  if (!pc) {
    createPeerConnection();
  }
  console.log("handleSignalingMessage--")
  console.log(data)
  console.log("handleSignalingMessage--添加文字")
  // 把websocket发送过来的消息，添加到页面展示
  addText(JSON.stringify(data))


  // 根据信令消息的类型进行处理
  switch (data.type) {
    case MessageType.Offer:
      handleOffer(data.data);
      break;
    case MessageType.Answer:
      handleAnswer(data.data);
      break;
    case MessageType.Candidate:
      handleCandidate(data.data);
      break;
  }
};

// 创建 RTCPeerConnection 实例
const createPeerConnection = () => {
  console.log("开始创建rtc连接")
  pc = new RTCPeerConnection({
    iceServers: [
      { urls: 'stun:stun.l.google.com:19302' },
      { urls: 'stun:stun1.l.google.com:19302' },
      { urls: 'stun:stun2.l.google.com:19302' },
      { urls: 'stun:stun3.l.google.com:19302' },
      { urls: 'stun:stun4.l.google.com:19302' }
    ]
  });
  console.log("创建rtc连接成功,pc")
  console.log(pc)
  // 添加本地流
  if (localStream) {
    console.log("开始添加本地流")
    localStream.getTracks().forEach(track => pc?.addTrack(track, localStream));
  }

  // 监听 ICE 候选
  pc.addEventListener('icecandidate', (event) => {
    console.log("设置候选者事件")
    if (event.candidate) {
      ws?.send({
        type: MessageType.Candidate,
        data:event.candidate,
        id:roomId.value,
      });
    }
  });
  pc.addEventListener('iceconnectionstatechange', (event:any) => {
    prettierLog({
      msg:"pc收到iceconnectionstatechange:connected",type:"warn"
    });
    const iceConnectionState = event.currentTarget.iceConnectionState;
    if (iceConnectionState === 'connected') {
      // // ICE 代理至少对每个候选发现了一个可用的连接，此时仍然会继续测试远程候选以便发现更优的连接。同时可能在继续收集候选。
      console.log("iceConnectionState webrtc接成功")
    }else if(iceConnectionState === 'disconnected'){
      console.log("iceConnectionState 连接断开")
    }else if(iceConnectionState === 'failed'){
      console.log("iceConnectionState 连接失败")
    }else if(iceConnectionState === 'closed'){
      console.log("iceConnectionState 连接关闭")
    }else if(iceConnectionState === 'completed'){
      console.log("iceConnectionState 连接完成")
    }

  })

  // 监听连接状态变化
  pc.addEventListener('connectionstatechange', (event:any) => {
    console.log('pc的connectionstatechange事件:', event);
    const connectionState = event.currentTarget.connectionState;
    prettierLog({
      msg:"pc收到connectionstatechange:connected",type:"warn"
    });

    if (connectionState === 'connected') {
      // // ICE 代理至少对每个候选发现了一个可用的连接，此时仍然会继续测试远程候选以便发现更优的连接。同时可能在继续收集候选。
      console.log("connectionState webrtc接成功")
    }else if(connectionState === 'disconnected'){
      console.log("connectionState 连接断开")
    }else if(connectionState === 'failed'){
      console.log("connectionState 连接失败")
    }else if(connectionState === 'closed'){

    }
  });

  // 监听远程流
  pc.addEventListener('track', (event:RTCTrackEvent) => {
    // 将远程流绑定到远程视频元素上
    console.log('track事件的event', event);
    console.log('track事件的stream', event.streams[0]);
    console.log('track事件的视频轨', event.streams[0].getVideoTracks());
    console.log('track事件的音频轨', event.streams[0].getAudioTracks());
    if (remoteVideo.value) {
      remoteVideo.value.srcObject =event.streams[0];
      remoteVideo.value
    }
  });

  // 创建 offer
  pc.createOffer({
    offerToReceiveVideo: true
  })
    .then(offer => pc?.setLocalDescription(offer))
    .then(() => {
      ws?.send({
        type: MessageType.Offer,
        data: pc?.localDescription,
        id:roomId.value
      });
    })
    .catch(error => {
      console.error('Error creating offer:', error);
    });
};


// 处理 offer
const handleOffer = (data: any) => {
  console.log("接收到别人的offer")
  console.log(data)
  pc?.setRemoteDescription(new RTCSessionDescription(data))
    .then(() => {
      return pc?.createAnswer();
    })
    .then(answer => pc?.setLocalDescription(answer))
    .then(() => {
      ws?.send(
        { type: MessageType.Answer,
          data: pc?.localDescription ,
          id:roomId.value}
      );
    })
    .catch(error => {
      console.error('Error handling offer:', error);
    });
};

// 处理 answer
const handleAnswer = (data: any) => {
  console.log("接收到别人的answer",)
  console.log(data)
  pc?.setRemoteDescription(new RTCSessionDescription(data))
    .catch(error => {
      console.error('Error handling answer:', error);
    });
};

// 处理 ICE 候选
const handleCandidate = (data: any) => {
  console.log("接收到别人的candidate")
  console.log(data)
  pc?.addIceCandidate(new RTCIceCandidate(data))
    .catch(error => {
      console.error('Error adding ICE candidate:', error);
    });
};

const addText=(text: any)=>{
  console.log("addText--")
  textArea.value = textArea.value + text + "\n";
  console.log(textArea.value)
}

const prettierLog = (data: {
  msg: string;
  type?: 'log' | 'warn' | 'error' | 'success';
}) => {
  const { msg, type } = data;
  if (type === 'success') {
    console.log(
      `%c ` +
      `【WebRTCClass】${new Date().toLocaleString()},房间id:${
        roomId.value
      }` +
      ` %c ${msg} ` +
      `%c`,
      'background:#35495e ; padding: 1px; border-radius: 3px 0 0 3px;  color: #fff',
      'background:#41b883 ; padding: 1px; border-radius: 0 3px 3px 0;  color: #fff',
      'background:transparent'
    );
  } else {
    console[type || 'log'](
      `【WebRTCClass】${new Date().toLocaleString()},房间id:${roomId.value}`,
      msg
    );
  }
};
</script>

<template>
  <div>
    <el-row>
      <el-col :span="12">
        <video class="video" ref="localVideo"></video>
      </el-col>
      <el-col :span="12">
        <video class="video" ref="remoteVideo" autoplay playsinline></video>
      </el-col>
    </el-row>
    <br>
    <el-form label-width="300px">
      <el-form-item label="请输入用户id">
        <el-input-number v-model="userId" aria-label="请输入用户id信息"></el-input-number>
      </el-form-item>
      <el-form-item label="请输入房间号">
        <el-input-number v-model="roomId" aria-label="请输入房间号"></el-input-number>
      </el-form-item>
    </el-form>
    <el-button @click="clickStart" type="primary">开始链接</el-button>
    <br>
    <el-text tag="mark">{{textArea}}</el-text>
  </div>
</template>

<style scoped lang="scss">
.video{
  width: 400px;
  height: 300px;
  border: #36ace1 1px solid;
}
</style>